import { extname } from 'path';
import { Browser, launch, executablePath, Page, HTTPResponse, GoToOptions, HTTPRequest } from 'puppeteer'
let browser: Promise<Browser>;
export const useBrowser = async (headless: boolean | 'new' = 'new') => {
    if (browser) return await browser;
    browser = launch({
        executablePath: executablePath(),
        headless: headless,
        devtools: false,
        ignoreDefaultArgs: ['--disable-extensions'],
        args: [
            '--no-sandbox',                    // 沙盒模式
            '--disable-setuid-sandbox',        // uid沙盒
            '--disable-dev-shm-usage',         // 创建临时文件共享内存
            '--disable-accelerated-2d-canvas', // canvas渲染
            '--disable-gpu',                   // GPU硬件加速
            '--disable-setuid-sandbox'
        ],
    });
    return browser;
}

export interface BrowserPageHandler<T> {
    (page: Page, browser: Browser): Promise<T>;
}

export const useBrowserPage = async <T>(handler: BrowserPageHandler<T>, headless: boolean | 'new' = 'new') => {
    const browser = await useBrowser(headless);
    let page = await browser.newPage();
    const result = await handler(page, browser);
    await page.close();
    return result;
}

export async function waitForSelector(page: Page, selector: string, max: number = 10) {
    let img = await page.waitForSelector(selector).catch(e => {
        return null;
    })
    let count: number = 0;
    while (!img) {
        await delay(1000)
        img = await page.waitForSelector(selector).catch(e => {
            return null;
        });
        count += 1;
    }
    return img;
}

export function delay(n: number) {
    return new Promise<void>((resolve, reject) => {
        setTimeout(() => resolve(), n)
    })
}


export async function getFromBrowserRRequest(
    url: string,
    cookies: any[],
    onRequest: (res: HTTPRequest) => Promise<void>,
    onResponse: (res: HTTPResponse) => Promise<void>,
    onPage: (page: Page) => Promise<void>,
    options: GoToOptions,
    headless: boolean | 'new' = 'new'
) {
    return await useBrowserPage(async (page, browser) => {
        await page.setCookie(...cookies);
        await page.setJavaScriptEnabled(true);
        await page.setRequestInterception(true);
        page.removeAllListeners()
        const ignoreExtnames: string[] = [
            '.ico', '.png', '.jpeg', '.jpg', '.css', '.svg', '.bmp', '.gif', '.ttf', '.eot', '.woff', '.woff2',
            '.mp3', '.mp4'
        ]
        await page.setViewport({
            width: 1325,
            height: 768
        });
        const list: any[] = []
        page.on('request', req => {
            const url = new URL(req.url())
            const path = url.pathname;
            const ext = extname(path).toLowerCase()
            if (req.url().startsWith('data:image')) {
                req.respond({
                    status: 200,
                    contentType: 'text/plain',
                    body: 'not found'
                })
            }
            if (ignoreExtnames.includes(ext)) {
                req.respond({
                    status: 200,
                    contentType: 'text/plain',
                    body: 'not found'
                })
            } else {
                list.push(onRequest(req))
                req.continue()
            }
        })
        page.on('response', function (res) {
            const url = new URL(res.url())
            const path = url.pathname;
            const ext = extname(path).toLowerCase()
            if (ignoreExtnames.includes(ext)) {
                return;
            }
            if (ext === '.js') {
                return;
            }
            if (res.request().method().toUpperCase() === 'OPTIONS') {
                return;
            }
            list.push(onResponse(res))
        });
        await page.goto(url, options)
        await onPage(page);
        await Promise.all(list)
    }, headless)
}